#include "FieldPlayer.h"
#include "FieldPlayerStates.h"
#include "Fonts.h"
#include "Params.h"
#include "Team.h"
#include "Utils.h"
#include <vector>
#include "Ball.h"

using namespace std;

FieldPlayer::FieldPlayer(GameState* game, Team* team, int homeRegionId, sf::Color drawColor)
			: BasePlayer(game, team, homeRegionId, drawColor, Params::PlayerMaxSpeed)
{
	//Init player's FSM
	m_FSM = new StateMachine<FieldPlayer>(this);
	
	m_FSM->SetGlobalState(GlobalPlayerState::Istance());
	m_FSM->SetCurrentState(Idle::Istance());
	m_FSM->SetPreviousState(NULL);

	pVal = sf::Text("",*Fonts::Istance()->GetFont("Consola"), 14); //// FIXME TEMP!! JUST FOR DEBUG !
	pValNum = 0.f; //// FIXME TEMP!! JUST FOR DEBUG !
}

FieldPlayer::~FieldPlayer()
{
	delete m_FSM;
}

void FieldPlayer::SetUserControl(bool controlled)
{
	if(controlled)	m_FSM->ChangeState(UserControlled::Istance());
	else			m_FSM->ChangeState(Idle::Istance());
}

/* Send player to its home, if not busy in most important actions */
void FieldPlayer::ToHome()
{
	if (m_FSM->IsInState(*Idle::Istance()))
	{
		//SetTarget(m_home->RandomCenterPosition());
		m_FSM->ChangeState(Idle::Istance());
	}
	
}

void FieldPlayer::CalculateInterposeWeight()
{
	if(!m_team->InControl()){
		if (m_team->DistBallToHomeGoal() <= Params::HotRegion )Steering()->SetInterposeWeight( 0.8f - (m_team->DistBallToHomeGoal() * 0.001f ) );
		else Steering()->SetInterposeWeight( 0.3f );

		Steering()->SetInterposeTo(Ball::Istance()->GetPosition());
	}
	else 
	{
		
		if( m_team->DistBallToHomeGoal() <= Params::HotRegion ) 
		{
			Vector2 to(Ball::Istance()->GetPosition().x ,Steering()->GetInterposeFrom().y);
			float weight = (Ball::Istance()->GetPosition() - Steering()->GetInterposeFrom()).Length() / (to - Steering()->GetInterposeFrom()).Length();
			Steering()->SetInterposeWeight(-0.4f+weight);
			Steering()->SetInterposeTo(to);
		}
		else if(m_team->OpponentTeam()->DistBallToHomeGoal() <= Params::HotRegion) 
		{
			Steering()->SetInterposeWeight(0.25f);
			Steering()->SetInterposeTo(Ball::Istance()->GetPosition());
		}
		else 
		{
			Steering()->SetInterposeWeight(0.3f);
			Steering()->SetInterposeTo(Ball::Istance()->GetPosition());
		}
		
	}	
}

/*	FALSE if there is an opponent FIELDplayer between player and opponent goal. Goalkeeper not checked.
	TRUE otherwise*/
Vector2 FieldPlayer::FindShot()
{
	Vector2 ballPos = Ball::Istance()->GetPosition();
	if (IsInHotRegion())
		//((ballPos - m_team->OpponentGoal()->Center()).Length() < Params::PlayerShotRange)
	{
		Vector2 centralDirection = (m_team->OpponentGoal()->Center() - ballPos).NormalizeCopy();
		Vector2 firstPostDirection = (m_team->OpponentGoal()->GetFirstPost(ballPos) - ballPos).NormalizeCopy();
		Vector2 secondPostDirection = (m_team->OpponentGoal()->GetSecondPost(ballPos) - ballPos).NormalizeCopy();

		if (CanShootToward(centralDirection))
			return centralDirection;
		else if (CanShootToward(firstPostDirection))
			return firstPostDirection;
		else if (CanShootToward(secondPostDirection))
			return secondPostDirection;
	}
	return Vector2::ZERO;
}

bool FieldPlayer::CanShootToward(Vector2 toward)
{
	vector<BasePlayer*> enemies = m_team->OpponentTeam()->Players();

	for ( vector<BasePlayer*>::iterator it = enemies.begin(); it != enemies.end(); ++it)
	{
		Vector2 enDirection = ((*it)->GetPosition() - Ball::Istance()->GetPosition()).NormalizeCopy();

		//we find cos between shotDirection and EnemyDirection
		float cosBeta = toward.DotProduct(enDirection);

		if (cosBeta >= Params::ShotInterceptRange)
		{
			return false;
		}
	}
	return true;
}

/*	Check it there is an other mate player in a better position, NULL otherwise.
If one is found, check if there is a safe pass to him. NULL otherwise.*/
BasePlayer* const FieldPlayer::FindPass()
{
	BasePlayer* toPass = NULL;
	
	//Now we give a score to player position, valuating his safeness and distance to OpponentGoal. 
	float bestPass = (0.0857f * DistToHomeGoal());//it weighs ~60% on total

	pValNum = -bestPass;	//FIXME!!! JUST FOR DEBUG!
	
	float safeness = 50.f; //completely safe.
	
	vector<BasePlayer*> opponents = m_team->OpponentTeam()->Players();

	for ( vector<BasePlayer*>::iterator it = opponents.begin(); it != opponents.end(); ++it)
	{
		if( (*it)->DistToBall() < Params::PlayerSafenessRange && 
			DistToOppGoal() > (*it)->DistToHomeGoal()- Params::TackleRange -5.f &&
			!(*it)->IsWaiting())
		{
			m_team->OpponentTeam()->TeamPlayerClosestToBall()->DistToBall();
			if ( safeness > (*it)->DistToBall())
			{
				safeness = (*it)->DistToBall();
			}
		}
	}
	bestPass += safeness;

	pVal.SetString(NumberToString(bestPass));	//FIXME!!! JUST FOR DEBUG!
	pValNum += bestPass;	//FIXME!!! JUST FOR DEBUG!

	//Search for a better positioned team mate. if founded check how much pass is safe. 
	vector<BasePlayer*> mates = m_team->Players();
	
	for ( vector<BasePlayer*>::iterator it = mates.begin(); it != mates.end(); ++it)
	{
		if ((*it) !=  this)
		{
			float currentPassValue = CanPass((*it));
			if (bestPass < currentPassValue)
			{
				bestPass = currentPassValue;
				toPass = (*it);
			}
			(*it)->pVal.SetString(NumberToString(currentPassValue));//FIXME!!! JUST FOR DEBUG!
		}
	}

	return toPass;
}

void FieldPlayer::Update(const sf::Input& input)
{
	//if(!IsUserControlled())	
		m_FSM->Update();
	BasePlayer::Update(input);
}

void FieldPlayer::OnDraw(sf::RenderWindow& renderWindow)
{

	//renderWindow.SaveGLStates();
	/*sf::Shape safe = sf::Shape::Circle(sf::Vector2f(m_pos.x,m_pos.y), 
										Params::PlayerSafenessRange,
										sf::Color(250,150,0,100), 1.f);
	renderWindow.Draw(safe);*/

	//pVal.SetPosition(m_pos.x, m_pos.y -15); //FIXME!! JUST FOR DEBUG
	//renderWindow.Draw(pVal); //FIXME!! JUST FOR DEBUG

	//renderWindow.RestoreGLStates();

	BasePlayer::OnDraw(renderWindow);
}
